package qrcodes

import (
	"encoding/base64"
	"fmt"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"github.com/nfnt/resize"
	"github.com/skip2/go-qrcode"
	"golang.org/x/image/draw"
	"image"
	"image/color"
	"image/png"
	"log"
	"os"
)

// GetQRCodeIO 返回图片字节 content-二维码内容   level-容错级别(越高越好),Low,Medium,High,Highest   size-像素单位
func GetQRCodeIO(content string, level qrcode.RecoveryLevel, size int) string {
	var png []byte
	png, err := qrcode.Encode(content, level, size)
	if err != nil {
		return ""
	}
	res := base64.StdEncoding.EncodeToString(png)
	fmt.Println(res)
	return res
}

// GetQRCodeFile content-二维码内容   level-容错级别,Low,Medium,High,Highest   size-像素单位  outPath-输出路径
func GetQRCodeFile(content, outPath string, level qrcode.RecoveryLevel, size int) interface{} {
	err := qrcode.WriteFile(content, level, size, outPath)
	if err != nil {
		return err.Error()
	}
	return nil
}

// GetQRCodeCustom content-二维码内容   level-容错级别,Low,Medium,High,Highest   size-像素单位  outPath-输出路径   bColor-前景颜色   gColor-背景颜色
func GetQRCodeCustom(content, outPath string, level qrcode.RecoveryLevel, size int, bColor, gColor color.Color) interface{} {
	err := qrcode.WriteColorFile(content, level, size, bColor, gColor, outPath)
	if err != nil {
		return err.Error()
	}
	return nil
}

// CreateQrCodeWithLogo 带logo的二维码图片生成 content-二维码内容   level-容错级别,Low,Medium,High,Highest   size-像素单位  outPath-输出路径  logoPath-logo文件路径
func CreateQrCodeWithLogo(content, logoPath, outPath string, level qrcode.RecoveryLevel, size int) error {
	code, err := qrcode.New(content, level)
	if err != nil {
		return err
	}
	//设置文件大小并创建画板
	qrcodeImg := code.Image(size)
	outImg := image.NewRGBA(qrcodeImg.Bounds())

	//读取logo文件
	logoFile, err := os.Open(logoPath)
	if err != nil {
		return err
	}
	logoImg, _, err := image.Decode(logoFile)
	logoImg = resize.Resize(uint(size/6), uint(size/6), logoImg, resize.Lanczos3)

	//logo和二维码拼接
	draw.Draw(outImg, outImg.Bounds(), qrcodeImg, image.Pt(0, 0), draw.Over)
	offset := image.Pt((outImg.Bounds().Max.X-logoImg.Bounds().Max.X)/2, (outImg.Bounds().Max.Y-logoImg.Bounds().Max.Y)/2)
	draw.Draw(outImg, outImg.Bounds().Add(offset), logoImg, image.Pt(0, 0), draw.Over)

	f, err := os.Create(outPath)
	if err != nil {
		return err
	}
	png.Encode(f, outImg)
	return nil
}

// CreateQrCodeCustomWithLogo 带logo的二维码图片生成 content-二维码内容   level-容错级别,Low,Medium,High,Highest   size-像素单位  outPath-输出路径  logoPath-logo文件路径
func CreateQrCodeCustomWithLogo(content, logoPath, outPath string, level qrcode.RecoveryLevel, size int) interface{} {
	code, err := qrcode.New(content, level)
	if err != nil {
		return err.Error()
	}
	qrcodeImg := code.Image(size)
	outImg := image.NewRGBA(qrcodeImg.Bounds())

	logoFile, err := os.Open(logoPath)
	if err != nil {
		panic(err)
	}
	logoImg, _, err := image.Decode(logoFile)
	logoImg = resize.Resize(uint(size/6), uint(size/6), logoImg, resize.Lanczos3)

	//添加方形画板
	circleImg := code.Image(size/6 + 5)
	outCircleImg := image.NewRGBA(circleImg.Bounds())
	//logo切为圆形
	draw.DrawMask(outCircleImg, outCircleImg.Bounds(), logoImg, image.ZP, &Circle{image.Pt(size/12, size/12), size / 12}, image.ZP, draw.Over)

	//logo和二维码拼接
	draw.Draw(outImg, outImg.Bounds(), qrcodeImg, image.Pt(0, 0), draw.Over)
	offset := image.Pt((outImg.Bounds().Max.X-outCircleImg.Bounds().Max.X)/2, (outImg.Bounds().Max.Y-logoImg.Bounds().Max.Y)/2)
	draw.Draw(outImg, outImg.Bounds().Add(offset), outCircleImg, image.Pt(0, 0), draw.Over)

	//再次添加画板
	backImg := code.Image(size - size/10)
	outBackImg := image.NewRGBA(backImg.Bounds())
	draw.DrawMask(outBackImg, outBackImg.Bounds(), outImg, image.ZP, &Rectangle{image.Pt((size+(size/10))/2, (size+(size/10))/2), size/2 - size/20, size/2 - size/20}, image.ZP, draw.Over)

	f, err := os.Create(outPath)
	if err != nil {
		return err.Error()
	}
	png.Encode(f, outBackImg)
	return nil
}

var (
	fontKai *truetype.Font // 字体
)

func CreateQrCodeCustomWithLogoPoster(content, logoPath, outPath string, level qrcode.RecoveryLevel, size int, text2 string) error {
	code, err := qrcode.New(content, level)
	if err != nil {
		return err
	}
	//设置文件大小并创建画板
	qrcodeImg := code.Image(size)
	outImg := image.NewRGBA(qrcodeImg.Bounds())

	//读取logo文件
	logoFile, err := os.Open(logoPath)
	if err != nil {
		panic(err)
	}
	logoImg, _, err := image.Decode(logoFile)
	logoImg = resize.Resize(uint(size/4), uint(size/4), logoImg, resize.Lanczos3)

	//logo和二维码拼接
	draw.Draw(outImg, outImg.Bounds(), qrcodeImg, image.Pt(0, 0), draw.Over)
	offset := image.Pt((outImg.Bounds().Max.X-logoImg.Bounds().Max.X)/2, (outImg.Bounds().Max.Y-logoImg.Bounds().Max.Y)/2)
	draw.Draw(outImg, outImg.Bounds().Add(offset), logoImg, image.Pt(0, 0), draw.Over)

	f, err := os.Create(outPath)
	if err != nil {
		return err
	}
	png.Encode(f, outImg)

	// 根据路径打开模板文件
	templateFile, err := os.Open("public/bg.png")
	if err != nil {
		panic(err)
	}
	defer templateFile.Close()
	// 解码
	templateFileImage, err := png.Decode(templateFile)
	if err != nil {
		panic(err)
	}
	// 新建一张和模板文件一样大小的画布
	newTemplateImage := image.NewRGBA(templateFileImage.Bounds())
	// 将模板图片画到新建的画布上
	draw.Draw(newTemplateImage, templateFileImage.Bounds(), templateFileImage, templateFileImage.Bounds().Min, draw.Over)

	// 加载字体文件  这里我们加载两种字体文件
	fontKai, err = loadFont("public/verdana.ttf")
	if err != nil {
		log.Panicln(err.Error())
		return err
	}

	// 向图片中写入文字
	// 在写入之前有一些准备工作
	c := freetype.NewContext()
	c.SetClip(newTemplateImage.Bounds())
	c.SetDst(newTemplateImage)
	// 设置字体颜色
	c.SetSrc(image.Black)
	// 设置字体分辨率
	c.SetDPI(85)
	// 设置字体大小
	c.SetFontSize(18)
	// 设置字体样式，就是我们上面加载的字体
	c.SetFont(fontKai)
	//  正式写入文字
	// 参数1：要写入的文字
	// 参数2：文字坐标

	text := "北方人预订系统"
	qy := "推荐单位"
	//text2 = "中国石油天然气股份有限公司黑龙江销售分公司"

	c.DrawString(text, freetype.Pt((400-charactortype(text))/2, 380))

	c.DrawString(qy, freetype.Pt((400-charactortype(qy))/2, 420))

	maps := make(map[int]string)
	i := 1
	k := 0
	for _, v := range text2 {
		if i%15 == 0 {
			k++
		}
		maps[k] += string(v)
		i++
	}

	y := 420
	for _, v := range maps {
		y = y + 25
		c.DrawString(v, freetype.Pt((400-charactortype(v))/2, y))
	}

	// 读取二维码图片
	erCodeTemplateFile, err := os.Open(outPath)
	if err != nil {
		panic(err)
	}
	defer templateFile.Close()
	// 解码
	imageData, err := png.Decode(erCodeTemplateFile)
	if err != nil {
		panic(err)
	}
	//   2、重新调整要粘贴图片尺寸
	imageData = resize.Resize(350, 350, imageData, resize.Lanczos3)
	//  粘贴缩略图
	draw.Draw(newTemplateImage,
		newTemplateImage.Bounds().Add(image.Pt(25, 10)),
		imageData,
		imageData.Bounds().Min,
		draw.Over)
	// 保存图片
	err = saveFile(newTemplateImage, outPath)
	if err != nil {
		return err
	}

	return nil
}

// 根据路径加载字体文件
// path 字体的路径
func loadFont(path string) (font *truetype.Font, err error) {
	var fontBytes []byte
	fontBytes, err = os.ReadFile(path) // 读取字体文件
	if err != nil {
		err = fmt.Errorf("加载字体文件出错:%s", err.Error())
		return
	}
	font, err = freetype.ParseFont(fontBytes) // 解析字体文件
	if err != nil {
		err = fmt.Errorf("解析字体文件出错,%s", err.Error())
		return
	}
	return
}

func saveFile(pic *image.RGBA, outPath string) error {
	dstFile, err := os.Create(outPath)
	if err != nil {
		fmt.Println(err)
	}
	defer dstFile.Close()
	err = png.Encode(dstFile, pic)
	if err != nil {
		return err
	}
	return nil
}

func charactortype(str string) int {
	a := len(str)
	b := a / 3
	if b > 15 {
		b = 15
	}
	return b * 20

}
